/*
 * Copyright (C) 2017
 *
 * Brick Yang <printfxxx@163.com>
 *
 * This program is free software. You can redistribute it and/or
 * modify it as you like.
 */

/**
 * @file	qbman.h
 * @brief	Header file for qbman driver
 */

#ifndef _QBMAN_H_
#define _QBMAN_H_

#include <linux/types.h>
#include <linux/device.h>

#include <soc/fsl/dpaa2-fd.h>

/* Definitions for parsing dequeue entries */
#define QBMAN_RESULT_MASK	0x7f
#define QBMAN_RESULT_DQ		0x60
#define QBMAN_RESULT_FQRN	0x21
#define QBMAN_RESULT_FQRNI	0x22
#define QBMAN_RESULT_FQPN	0x24
#define QBMAN_RESULT_FQDAN	0x25
#define QBMAN_RESULT_CDAN	0x26
#define QBMAN_RESULT_CSCN_MEM	0x27
#define QBMAN_RESULT_CGCU	0x28
#define QBMAN_RESULT_BPSCN	0x29
#define QBMAN_RESULT_CSCN_WQ	0x2a

/* QBMan portal management command codes */
#define QBMAN_CR_ACQUIRE	0x30

/* Management command result codes */
#define QBMAN_MC_RSLT_OK	0xf0

/* QBMan portal release command codes */
#define QBMAN_RCR_RELEASE	0x20

/* QBMan portal enqueue command codes */
#define QBMAN_EQCR_EMPTY	0
#define QBMAN_EQCR_RESPONSE	1
#define QBMAN_EQCR_REJECT	2

/* qbman software portal descriptor structure */
struct qbman_swp_desc {
	void *cena_bar;
	void *cinh_bar;
	size_t cena_size;
	size_t cinh_size;
	unsigned long flags;
	#define SWP_F_EST	0x01
	#define SWP_F_DE	0x02
	#define SWP_F_RCR_VB	0x04
	#define SWP_F_EQCR_VB	0x08
	#define SWP_F_DQRR_VB	0x10
	#define SWP_F_MEMBACK	0x20
	u32 qman_version;
};

/* structure of enqueue command */
struct qbman_enq_cmd {
	u8 verb;
	u8 dca;
	__le16 seqnum;
	__le16 orpid;
	__le16 reserved;
	__le32 tgtid;
	__le32 tag;
	__le16 qdbin;
	u8 qpri;
	u8 reserved2[3];
	u8 wae;
	u8 rspid;
	__le64 rsp_addr;
	struct dpaa2_fd fd;
};

/* structure of buffer release command */
struct qbman_rel_cmd {
	u8 verb;
	u8 reserved;
	__le16 bpid;
	__le32 reserved2;
	__le64 buf[7];
};

/* structure of buffer acquire command */
struct qbman_acq_cmd {
	u8 verb;
	u8 reserved;
	__le16 bpid;
	u8 num;
	u8 reserved2[59];
};

/* structure of buffer acquire response */
struct qbman_acq_resp {
	u8 verb;
	u8 rslt;
	__le16 reserved;
	u8 num;
	u8 reserved2[3];
	__le64 buf[7];
};

/* portal data structure */
struct qbman_swp {
	const struct qbman_swp_desc *desc;
	void __iomem *addr_cena;
	void __iomem *addr_cinh;

	/* Push dequeues */
	u32 sdq;

	/* CR */
	struct {
		u8 valid_bit;
	} cr;

	/* DQRR */
	struct {
		u8 pi, ci, fi;
		u8 pi_ci_mask;
		u8 valid_bit;
	} dqrr;

	/* EQCR */
	struct {
		u8 pi, ci, fi;
		u8 pi_ci_mask;
		u8 valid_bit;
	} eqcr;

	/* RCR */
	struct {
		u8 pi, ci, fi;
		u8 pi_ci_mask;
		u8 valid_bit;
	} rcr;
};

static inline void qbman_swp_cmd_zero(void __iomem *p)
{
	u32 *w = p;

	w[0] = 0;
	w[1] = 0;
	w[2] = 0;
	w[3] = 0;
	w[4] = 0;
	w[5] = 0;
	w[6] = 0;
	w[7] = 0;
	w[8] = 0;
	w[9] = 0;
	w[10] = 0;
	w[11] = 0;
	w[12] = 0;
	w[13] = 0;
	w[14] = 0;
	w[15] = 0;
}

struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d);
void qbman_swp_finish(struct qbman_swp *s);
void __iomem *qbman_swp_cr_next(struct qbman_swp *s, u8 *cmd_verb);
const void __iomem *qbman_swp_rr_next(struct qbman_swp *s, u8 cmd_verb);
void __iomem *qbman_swp_eqcr_next(struct qbman_swp *s, u8 *cmd_verb);
void __iomem *qbman_swp_rcr_next(struct qbman_swp *s, u8 *cmd_verb);
const void __iomem *qbman_swp_dqrr_next(struct qbman_swp *s);
void qbman_swp_cr_submit(struct qbman_swp *s, void __iomem *p, u8 cmd_verb);
int qbman_swp_eqcr_submit(struct qbman_swp *s, void __iomem *p, u8 cmd_verb, bool flush);
int qbman_swp_rcr_submit(struct qbman_swp *s, void __iomem *p, u8 cmd_verb, bool flush);
int qbman_swp_dqrr_consume(struct qbman_swp *s, const void __iomem *p, bool flush);
void qbman_swp_push_get(struct qbman_swp *s, u8 idx, bool *en);
void qbman_swp_push_set(struct qbman_swp *s, u8 idx, bool en);

#endif	/* _QBMAN_H_ */
